package article10.equals;


import java.awt.*;
import java.util.ArrayList;
import java.util.List;

/**
 * 第10条 覆盖equals时请遵守通用约定
 *
 * 期望的的结果：
 * 1.类的每个实例本质上都是唯一的。
 * 2.类没有提供“逻辑相等”的测试功能。
 * 3.超类已经覆盖了equals，超累的行为对这个类也是合适的。
 * 4.类是私有的，或者包级私有的，可以确定它的equals方法永远不会被调用。
 *
 *
 * 在覆盖 equals 方法的时候，必须要遵守它的通用约定：
 * 1.自反性（reflexive），对于任何非null的引用值x,x.equals(x)必须返回true.
 * 2.对称性（symmetric）：对于任何非null的引用值，当且仅当y.equals(x)返true 时, x.equals(y)必须返回 true
 * 3.传递性（transitive）：对于任何非null的引用值x、y、z，如果x.equals(y)返回* true，并且y.equals(z)也返回true，那么x.equals(z)也必须返回true
 * 4.一致性（consistent）：对于任何非null的引用值x、y，只要equals的比较操作在对象所用的i西南西没有被修改，
 *   多次调用x.equals(y)就会一致的返回true，或者false
 * 5.对于任何非null的引用值x,x.equals(null)必须返回false
 *
 * 一旦违反了equals约定，当其他对象面对你的对象时，你完全不知道这些对象的行为会怎么样。
 *
 * 注意，你可以在一个抽象（abstract）类的子类中增加新的值组件且不连反 equals约定。对于根据第 23 条的建议而得到的那种类层次结构来说，
 * 这一点非常重要。例如，你可能有一个抽象的Shape类，它没有任何值组件，Circle子类添加了一个 radius 域，Reetangle 子类添加了
 * length width 只要不可能直接创建超类的实例，前面所述的种种问题就都不会发生
 *
 * @Author: cctv
 * @Date: 2019/3/29 15:48
 */
public class Demo {
    public static void main(String[] args) {
        // 1.自反性 说明对象必须等于其自身。
        // 2.对称性 任何两个对象对于它们是否相等的问题都必须保持一致
        CaseInsensitiveString cis = new CaseInsensitiveString("polish");
        String s = "polish";
        // 书中这里说的true  但是jdk8是false
        System.out.println(cis.equals(s));
        System.out.println(s.equals(cis));
        System.out.println(cis.equals1(s));

        List<CaseInsensitiveString> list = new ArrayList<>();
        list.add(cis);
        //在其他的实现中，它有可能返回 true ，或者抛出一个运行时异常
        System.out.println(list.contains(s));



        System.out.println("违反对称性");
        Point p = new Point(1,2);
        ColorPoint cp = new ColorPoint(1,2, Color.RED);
        System.out.println(p.equals(cp));
        System.out.println(cp.equals(p));

        // 3.传递性 如果一个对象等于第二个对象，而第二个对象又等于第三个对象，则第一个对象一定等于第三个对象
        System.out.println("违反传递性");
        ColorPoint cp1 = new ColorPoint(1,2, Color.BLUE);
        System.out.println(cp.equals1(p));
        System.out.println(p.equals(cp1));
        System.out.println(cp.equals1(cp1));
        // 我们无法在扩展可实例化的类的同时，既增加新的值组件，同时又保留equals约定
        System.out.println("违反里氏替换原则");
        System.out.println(cp.equals2(cp1));

        System.out.println("里氏替换原则");
        ColorPoint1 cp2 = new ColorPoint1(1,2,Color.BLACK);
        System.out.println(cp2.equals(p));
        System.out.println(p.equals(cp2));
        System.out.println(cp2.equals(cp));


        // 4.一致性 如果两个对象相等，它们就必须始终保持相等，除非它们中有一个对象（或者两个都）被修改了。换句话说，可变对象
        // 在不同的时候可以与不同的对象相等，而不可变对象则不会这样。
        // 无论类是否是不可变的 都不要使equals方法依赖于不可靠的资源

        // 5.非空性 意思是所有的对象都不能等于null
        //        @Override
        //        public boolean equals(Object o){
        //            if(o==null)
        //                return false;
        //        }

        //        @Override
        //        public boolean equals(Object o){
        //            if(!o instanceof MyType)
        //                return false;
        //            MyTpye mt = (MyType) o;
        //            ...
        //        }


//        结合所有这些要求，得出了以下实现高质量equals方法的诀窍：
//        1.使用==操作符检查“参数是否为这个对象的引用”
//        2.使用instanceof操作符检查“参数是否为正确的类型”
//        3.把参数转换成正确的类型
//        4.对于该类中的每一个“关键”域，检查参数中的域是否与该对象中对应的域相匹配

//        在编写完 equals 方法之后，应该问自己三个问题：它是否是对称的、传递的、一致的？

    }

}

